﻿//Chỉ dùng tại frmNhapVeHuy_DL

using System;
using System.Data;
using System.Data.SqlClient;
using System.Linq;

namespace prjKQXS_DLL.Truyen_thong
{
    public class clsHuyVeDL
    {
        static SqlConnection _conn = null;

        public delegate void NewMessage();
        public event NewMessage OnNewMessage;
        //Cài đặt event OnError để bắt các lỗi chưa được xử lý
        public delegate void OnErrorHandler(Exception e);
        public event OnErrorHandler OnError;

        //Cài đặt event OnAction để thông báo các trạng thái kết quả
        public delegate void OnActionHandler(SqlException e);
        public event OnActionHandler OnAction;

        public delegate void OnChangedDataHandler();
        public event OnChangedDataHandler OnChangedData;


        /// <summary>
        /// Bảng này được tạo từ dt_VeHuyDL_Part1 và dt_VeHuyDL_Part2
        /// </summary>
        public DataTable dt_VeHuyDL = new DataTable();

        /// <summary>
        /// <para>Bảng này kết hợp với bảng dt_VeHuyDL_Part2 dùng để tạo dt_VeHuyDL</para>
        /// <para>Được nạp dữ liệu một lần bởi LoadVeHuy_DL_Part1() khi lớp khởi tạo</para>
        /// </summary>
        public DataTable dt_VeHuyDL_Part1 = new DataTable();

        /// <summary>
        /// Bảng này kết hợp với bảng dt_VeHuyDL_Part1 dùng để tạo dt_VeHuyDL, được nạp dữ liệu bởi LoadVeHuy_DL_Part2()
        /// </summary>
        private DataTable dt_VeHuyDL_Part2 = new DataTable();


        /// <summary>
        /// <para>Bảng này chứa thông tin MaCB, TenCB toàn công ty trong @Ngay</para>
        /// <para>Được nạp dữ liệu một lần bởi LoadVeHuy_CB khi lớp khởi tạo</para>
        /// </summary>
        private DataTable dt_CanBo = new DataTable();
        private DateTime NgayMoThuong = DateTime.Now.Date;
        public char MaDV = '%';


        /// <summary>
        /// Biến này để kiểm soát không cho đăng ký hơn 1 dependency, nếu không OnChange sẽ xảy ra nhiều lần không cần thiết.
        /// </summary>
        private string queue = "";


        /// <summary>
        /// 
        /// </summary>
        /// <param name="ngaymothuong">Ngày mở thưởng</param>
        public clsHuyVeDL(DateTime ngaymothuong)
        {
            enableServiceBorker();
            SqlDependency.Stop(BienTc.connString);  //Dừng lại toàn bộ dependency nếu có
            SqlDependency.Start(BienTc.connString); //Bắt đầu dependency 

            _conn = new SqlConnection(BienTc.connString);
            this.NgayMoThuong = ngaymothuong;
            LoadVeHuy_CB();
            LoadVeHuy_DL_Part1();
        }

        ~clsHuyVeDL()
        {
            SqlDependency.Stop(BienTc.connString);
        }

        private void enableServiceBorker()
        {
            SqlConnection conn = new SqlConnection(BienTc.connString);
            string database = conn.Database;
           // conn.ChangeDatabase("master");
            SqlCommand cmd = new SqlCommand( );
            cmd.Connection = conn;
            conn.Open();
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = "enableSqlBroker";

            try
            {
                cmd.ExecuteNonQuery();
            }
            catch (SqlException ex)
            {
                /* ex.Message:
                 * The Service Broker in database "KQXS_New" cannot be enabled because there is already an enabled Service Broker with the same ID.
                 * ALTER DATABASE statement failed.
                 * Nonqualified transactions are being rolled back. Estimated rollback completion: 100%.
                 */
                //if (ex.ErrorCode == -2146232060)
                //{
                //    cmd = new SqlCommand("ALTER DATABASE " + database + " SET NEW_BROKER WITH ROLLBACK IMMEDIATE", conn);
                //    cmd.ExecuteNonQuery();
                //    enableServiceBorker();
                //}
            }
        }


        /// <summary>
        /// Load ID, Ma_DaiLy, Ten_DaiLy, MaDV toàn công ty vào @Ngay
        /// </summary>
        /// <param name="Ngay">Ngày mở thưởng</param>
        /// <param name="MaDV">Truyền vào là % hoặc mã đơn vị tương ứng</param>
        /// <returns></returns>
        private void LoadVeHuy_DL_Part1()
        {
            try
            {
                SqlCommand cmd = new SqlCommand("proc_HuyVeDL_loadData", _conn);
                cmd.Parameters.AddWithValue("@Ngay", NgayMoThuong);
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Notification = null;
                SqlDependency dependency = new SqlDependency(cmd);
                dependency.OnChange += new OnChangeEventHandler(sqldependencyOnChange);
                dt_VeHuyDL_Part1.Clear();
                if (_conn.State != ConnectionState.Open) _conn.Open();
                dt_VeHuyDL_Part1.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection));
            }
            catch (SqlException e)
            {
                OnAction(e);
            }
            catch (Exception e)
            {
                OnError(e);
            }
        }

        private void sqldependencyOnChange(object sender, SqlNotificationEventArgs sqlNotificationEventArgs)
        {
            SqlDependency sqlDependency = sender as SqlDependency;
            sqlDependency.OnChange -= sqldependencyOnChange;
            queue = queue.Replace(sqlDependency.Id, "");// Fire the event
            if (OnNewMessage != null)
            {OnNewMessage();
            }
            sqlDependency.OnChange -= sqldependencyOnChange;
        }


        /// <summary>
        /// Load ID, SLVeNhan, SLVeHuy vào @Ngay cho dt_VeHuyDL_Part2
        /// </summary>
        /// <returns></returns>
        private void LoadVeHuy_DL_Part2()
        {
            try
            {
                if (_conn.State != ConnectionState.Open) _conn.Open();
                string sql = "SELECT ID, SLVeNhan, SLVeHuy FROM dbo.tblVESO_DL WHERE NgayMoThuong = @Ngay";
                SqlCommand cmd = new SqlCommand(sql, _conn);
                cmd.Parameters.AddWithValue("@Ngay", NgayMoThuong.Date);

                if (MaDV != '%')
                {
                    if (queue == "")
                    {
                        cmd.Notification = null;
                        // Create the dependency for this command
                        SqlDependency dependency = new SqlDependency(cmd);

                        // Add the event handler
                        dependency.OnChange += new OnChangeEventHandler(OnChange);
                        queue += dependency.Id;
                    }
                }

                dt_VeHuyDL_Part2.Clear();
                dt_VeHuyDL_Part2.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection));
            }
            catch (SqlException e)
            {
                OnAction(e);
            }
            catch (Exception e)
            {
                OnError(e);
            }
        }
        private void OnChange(object sender, SqlNotificationEventArgs e)
        {
            SqlDependency dependency = sender as SqlDependency;

            // Notices are only a one shot deal
            // so remove the existing one so a new 
            // one can be added
            dependency.OnChange -= OnChange;
            queue = queue.Replace(dependency.Id, "");// Fire the event
            if (OnNewMessage != null)
            {
                OnNewMessage();
            }
        }/// <summary>
        /// Ghép dữ liệu làm nguồn cho gcDaiLy (nạp dữ liệu vào dt_VeHuyDL)
        /// </summary>
        /// <returns></returns>
        public DataTable Reload_gcDaiLy()
        {
            try
            {
                LoadVeHuy_DL_Part2();

                if (MaDV == '%')
                {
                    var query = (from daily in dt_VeHuyDL_Part1.AsEnumerable()
                                join veso in dt_VeHuyDL_Part2.AsEnumerable() on daily.Field<int>("ID") equals veso.Field<int>("ID")
                                select new
                                {
                                    ID = daily.Field<int>("ID"),
                                    Ma_DaiLy = daily.Field<string>("Ma_DaiLy"),
                                    Ten_DaiLy = daily.Field<string>("Ten_DaiLy"),
                                    SLVeNhan = veso.Field<object>("SLVeNhan"),
                                    SLVeHuy = veso.Field<object>("SLVeHuy")
                                }).OrderBy(x=>x.Ma_DaiLy);

                    dt_VeHuyDL.Clear();
                    dt_VeHuyDL = clsCommon.CopyToDataTable(query);
                }
                else
                {
                    var query = from daily in dt_VeHuyDL_Part1.AsEnumerable()
                                join veso in dt_VeHuyDL_Part2.AsEnumerable() on daily.Field<int>("ID") equals veso.Field<int>("ID")
                                where daily.Field<string>("MaDV").Trim() == MaDV.ToString()
                                select new
                                {
                                    ID = daily.Field<int>("ID"),
                                    Ma_DaiLy = daily.Field<string>("Ma_DaiLy"),
                                    Ten_DaiLy = daily.Field<string>("Ten_DaiLy"),
                                    SLVeNhan = veso.Field<object>("SLVeNhan"),
                                    SLVeHuy = veso.Field<object>("SLVeHuy")
                                };

                    dt_VeHuyDL.Clear();
                    dt_VeHuyDL = clsCommon.CopyToDataTable(query);
                }
            }
            catch (SqlException e)
            {
                OnAction(e);
            }
            catch (Exception e)
            {
                OnError(e);
            }

            return dt_VeHuyDL;
        }

        private void MyOnChange(object sender, SqlNotificationEventArgs e)
        {
            SqlDependency dependency = sender as SqlDependency;
            dependency.OnChange -= MyOnChange;
            queue = queue.Replace(dependency.Id, "");

            OnChangedData();
        }

        //Hàm này sẽ xóa khi không còn dùng đến vào 2015
        //public int UpdateGiatriDV(int GiaVe, string KyHieu, char madv, DateTime ngay)
        //{
        //    int i = 0;
        //    try
        //    {
        //        if (conn.State != ConnectionState.Open) conn.Open();
        //        SqlCommand cmd = new SqlCommand("proc_HuyVe_DL_UpdateGiaTriDV", conn);
        //        cmd.CommandType = CommandType.StoredProcedure;
        //        cmd.Parameters.AddWithValue("@GiaVe", GiaVe);
        //        cmd.Parameters.AddWithValue("@KyHieu", KyHieu);
        //        cmd.Parameters.AddWithValue("@Madv", madv);
        //        cmd.Parameters.AddWithValue("@Ngay", ngay.Date);


        //        i = cmd.ExecuteNonQuery();
        //    }
        //    catch (SqlException e)
        //    {
        //        OnAction(e);
        //    }
        //    catch (Exception e)
        //    {
        //        OnError(e);
        //    }

        //    return i;
        //}


        /// <summary>
        /// Lưu vé
        /// </summary>
        /// <param name="GiaVe"></param>
        /// <param name="KyHieuVe"></param>
        public void SaveTicket(int GiaVe, string KyHieuVe)
        {
            try
            {
                #region Cài đặt adapter
                if (_conn.State != ConnectionState.Open) _conn.Open();
                SqlDataAdapter da = new SqlDataAdapter();

                SqlCommand cmdUpdate = new SqlCommand("UPDATE dbo.tblVESO_DL SET SLVeNhan = @SLVeNhan, SLVeHuy = @SLVeHuy, GiaVe=@GiaVe, KyHieu=@KyHieu WHERE ID = @ID", _conn);
                cmdUpdate.Parameters.Add("@ID", SqlDbType.VarChar, 10, "ID");  //<=> kiểu int
                cmdUpdate.Parameters.Add("@SLVeNhan", SqlDbType.VarChar, 10, "SLVeNhan");  //<=> kiểu int
                cmdUpdate.Parameters.Add("@SLVeHuy", SqlDbType.VarChar, 10, "SLVeHuy");  //<=> kiểu int
                cmdUpdate.Parameters.AddWithValue("@GiaVe", GiaVe);
                cmdUpdate.Parameters.AddWithValue("@KyHieu", KyHieuVe);
                da.UpdateCommand = cmdUpdate;
                #endregion

                da.Update(dt_VeHuyDL);  //Thực hiện lưu lại các thay đổi
            }
            catch (SqlException e)
            {
                OnAction(e);
            }
            catch (Exception e)
            {
                OnError(e);
            }
        }

        /// <summary>
        /// Nạp dữ liệu cho dt_CanBo (MaCB, TenCB toàn công ty trong @Ngay)
        /// </summary>
        /// <param name="Ngay"></param>
        /// <param name="MaDV"></param>
        /// <returns></returns>
        //private void LoadVeHuy_CB()
        //{
        //    //try
        //    //{
        //       // if (_conn.State != ConnectionState.Open) 
        //        _conn.ConnectionString = BienTc.connString;
        //            _conn.Open();
        //        string sql = "proc_HuyVeDL_LoadVeHuyCB";
        //        SqlCommand cmd = new SqlCommand(sql, _conn);
        //        cmd.CommandType = CommandType.StoredProcedure;
        //        cmd.Parameters.AddWithValue("@Ngay", NgayMoThuong);
        //        DataTable dt = new DataTable();
        //        //dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection));

        //        //var query = from canbo in dt.AsEnumerable()
        //        //            select new { MaCB = canbo.Field<string>("MaCB"), TenCB = canbo.Field<string>("TenCB") };

        //        //dt = clsCommon.CopyToDataTable(query);
        //        SqlDataAdapter sqladap = new SqlDataAdapter(cmd);
        //        sqladap.Fill(dt);
        //        dt_CanBo.Clear();
        //        dt_CanBo = dt;
        //        _conn.Close();
        //    //}
        //    //catch (SqlException e)
        //    //{
              
        //    //    OnAction(e);
        //    //}
        //    //catch (Exception e)
        //    //{
        //    //    OnError(e);
        //    //}
        //}

        private void LoadVeHuy_CB()
        {
            try
            {
                System.Data.SqlClient.SqlConnection.ClearAllPools();// xóa kết nối cũ, tạo kết nối mới
                // Có thể dùng câu lệnh SqlConnection.ClearAllPools(); trực tiếp trong SQL
                //Lỗi "A transport-level error has occurred when sending the request to the server.
                //(provider: Shared Memory Provider, error: 0 - The system cannot open the file.)"
                //SqlConnection conn = new SqlConnection();
                //conn.ConnectionString = BienTc.connString;//@"Data Source=TP3; Initial Catalog=KQXS_New3;User Id=sa;";
                //conn.Open();
                if (_conn.State != ConnectionState.Open) _conn.Open();
                string sql = "proc_HuyVeDL_LoadVeHuyCB";
                SqlCommand cmd = new SqlCommand(sql, _conn);
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.AddWithValue("@Ngay", NgayMoThuong);
                DataTable dt = new DataTable();
                //SqlDataAdapter da = new SqlDataAdapter();
                //da.SelectCommand = cmd;
                //da.Fill(dt);
                dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection));

                var query = from canbo in dt.AsEnumerable()
                            select new { MaCB = canbo.Field<string>("MaCB"), TenCB = canbo.Field<string>("TenCB") };

                dt = clsCommon.CopyToDataTable(query);

                dt_CanBo.Clear();
                dt_CanBo = dt;
            }
            catch (SqlException e)
            {
                OnAction(e);
            }
            catch (Exception e)
            {
                OnError(e);
            }
        }
        /// <summary>
        /// Hàm này giúp cập nhật lại giá trị SL vé nhận và SL vé hủy tương ứng bên gvCanBo mà không phải tải lại dữ liệu từ csdl.
        /// </summary>
        /// <returns></returns>
        public DataTable Reload_gcCanBo()
        {
            DataTable dt = new DataTable();

            try
            {
                var query = (from daily in dt_VeHuyDL.AsEnumerable()
                            join canbo in dt_CanBo.AsEnumerable() on daily.Field<string>("Ma_DaiLy").Substring(0, 2) equals canbo.Field<string>("MaCB")
                            group daily by new { MaCB = canbo.Field<string>("MaCB"), TenCB = canbo.Field<string>("TenCB") } 
                            into grCanBo
                            
                            select new
                            {
                                MaCB = grCanBo.Key.MaCB,
                                TenCB = grCanBo.Key.TenCB,
                                SLVeNhan = grCanBo.Sum(daily => daily.Field<object>("SLVeNhan") == null ? 0 : Convert.ToInt32(daily.Field<object>("SLVeNhan"))),
                                SLVeHuy = grCanBo.Sum(daily => daily.Field<object>("SLVeHuy") == null ? 0 : Convert.ToInt32(daily.Field<object>("SLVeHuy")))
                            }).OrderBy(c => c.MaCB);// xếp thứ tự mã 

                dt = clsCommon.CopyToDataTable(query);
                
            }
            catch (SqlException e)
            {
                OnAction(e);
            }
            catch (Exception e)
            {
                OnError(e);
            }

            return dt;
        }
        public static void UpdateGiaVe(DateTime Ngay, int giave)
        {
            try
            {
                if (_conn.State != ConnectionState.Open) _conn.Open();
                SqlCommand cmd = new SqlCommand(cmdText: String.Format("Update tblVESO_DL set Giave = {1} where NgayMoThuong = '{0}'", Ngay.ToString("yyyy-MM-dd"), giave), connection: _conn);
                cmd.ExecuteNonQuery();
            }
            catch (SqlException e)
            {
               // OnAction(e);
            }
            catch (Exception e)
            {
              //  OnError(e);
            }
        }

    }
}
